import Axios, {AxiosInstance, AxiosRequestConfig, AxiosResponse} from 'axios';
import {nacosNamingClient} from './index';
import * as Url from 'url';

class LoadBalanceHttpClient {

  public instance: AxiosInstance;

  public defaults: AxiosRequestConfig;

  constructor() {
    this.instance = Axios.create({});
    this.instance.interceptors.request.use((config) => {
      const url = Url.parse(config.url);

      if (url.protocol !== 'lb:' && url.protocol !== 'lbs:') {
        return config;
      }

      const serviceName = url.hostname;

      return nacosNamingClient.selectInstances(serviceName).then((instances) => {
        if (instances.length <= 0) {
          throw new Error(`not found instance by serviceName:${serviceName}`);
        }

        const index = Math.floor(Math.random() * instances.length);
        const instance = instances[index];
        const host = `${instance.ip}:${instance.port}`;
        const protocol = url.protocol === 'lbs:' ? 'https:' : 'http:';

        const newUrl = Url.format({
          ...url,
          host,
          protocol
        });

        config.headers.Accept = 'application/json';
        config.url = newUrl;

        return config;
      });
    }, (err) => {
      throw err;
    });
    this.instance.interceptors.response.use(({data: res}) => {
      return res;
    }, (err) => {
      throw err;
    });
  }

  public get<T = any, R = AxiosResponse<T>>(url: string,
                                            config?: AxiosRequestConfig): Promise<R> {
    return this.instance.get(url, config);
  }

  public post<T = any, R = AxiosResponse<T>>(url: string,
                                             data?: any,
                                             config?: AxiosRequestConfig): Promise<R> {
    return this.instance.post(url, data, config);
  }

  public put<T = any, R = AxiosResponse<T>>(url: string,
                                            data?: any,
                                            config?: AxiosRequestConfig): Promise<R> {
    return this.instance.put(url, data, config);
  }

  public delete(url: string, config?: AxiosRequestConfig): Promise<void> {
    return this.instance.delete(url, config);
  }
}

export default LoadBalanceHttpClient;
